package com.immediatus.graphics.buffer;

import com.immediatus.graphics.managers.BufferObjectManager;
import com.immediatus.graphics.util.OpenGLWrapper;
import com.immediatus.util.FastFloatBuffer;

import javax.microedition.khronos.opengles.GL11;


public abstract class BufferObject{
    private static final int[] HARDWAREBUFFERID_FETCHER = new int[1];

    protected final int[] _BufferData;
    protected final FastFloatBuffer _FloatBuffer;

    private final int _drawType;
    private int _hardwareBufferID = -1;
    private boolean _loadedToHardware;
    private boolean _hardwareBufferNeedsUpdate = true;
    private boolean _managed;

    public BufferObject(final int capacity_, final int drawType_, final boolean managed_){
        this._drawType = drawType_;
        this._managed = managed_;
        this._BufferData = new int[capacity_];
        this._FloatBuffer = new FastFloatBuffer(capacity_);

        if (managed_){
            this.loadToActiveBufferObjectManager();
        }
    }

    public boolean isManaged(){
        return this._managed;
    }

    public void setManaged(final boolean managed_){
        this._managed = managed_;
    }

    public FastFloatBuffer getFloatBuffer(){
        return this._FloatBuffer;
    }

    public int getHardwareBufferID(){
        return this._hardwareBufferID;
    }

    public boolean isLoadedToHardware(){
        return this._loadedToHardware;
    }

    public void setLoadedToHardware(final boolean loadedToHardware_){
        this._loadedToHardware = loadedToHardware_;
    }

    public void setHardwareBufferNeedsUpdate(){
        this._hardwareBufferNeedsUpdate = true;
    }

    public void selectOnHardware(final GL11 gl11_){
        final int hardwareBufferID = this._hardwareBufferID;
        if (hardwareBufferID == -1){
            return;
        }

        OpenGLWrapper.bindBuffer(gl11_, hardwareBufferID);

        if (this._hardwareBufferNeedsUpdate){
            this._hardwareBufferNeedsUpdate = false;
            synchronized (this){
                OpenGLWrapper.bufferData(gl11_, this._FloatBuffer.Buffer, this._drawType);
            }
        }
    }

    public void loadToActiveBufferObjectManager(){
        BufferObjectManager.getActiveInstance().loadBufferObject(this);
    }

    public void unloadFromActiveBufferObjectManager(){
        BufferObjectManager.getActiveInstance().unloadBufferObject(this);
    }

    public void loadToHardware(final GL11 gl11_){
        this._hardwareBufferID = this.generateHardwareBufferID(gl11_);
        this._loadedToHardware = true;
    }

    public void unloadFromHardware(final GL11 gl11_){
        this.deleteBufferOnHardware(gl11_);
        this._hardwareBufferID = -1;
        this._loadedToHardware = false;
    }

    private void deleteBufferOnHardware(final GL11 gl11_){
        OpenGLWrapper.deleteBuffer(gl11_, this._hardwareBufferID);
    }

    private int generateHardwareBufferID(final GL11 gl11_){
        gl11_.glGenBuffers(1, HARDWAREBUFFERID_FETCHER, 0);
        return HARDWAREBUFFERID_FETCHER[0];
    }
}
